package cn.edu.dutir.lucene;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.WildcardQuery;

public class LuceneIndexSearcher {
	static Analyzer analyzer = new StandardAnalyzer();

	public static void main(String args[]) throws IOException, ParseException {
		String usage = "Usage: java cn.edu.dutir.unit.lucene.LuceneIndexSearcher <-index_dir>";
		if (args.length == 0) {
			System.out.println(usage);
			System.exit(0);
		}

		File indexDir = new File(args[0]);
		IndexReader reader = IndexReader.open(indexDir);
		org.apache.lucene.search.IndexSearcher searcher = null;
		searcher = new org.apache.lucene.search.IndexSearcher(reader);

		BufferedReader in = null;
		in = new BufferedReader(new InputStreamReader(System.in));
		String line = null;
		while (true) {
			System.out.print("Query:\t");
			line = in.readLine();
			if (line == null || line.equalsIgnoreCase("exit")
					|| line.equalsIgnoreCase("quit")) {
				break;
			}
			if (line.equals("") || line.trim().length() == 0) {
				continue;
			}

			Hits hits = searcher.search(queryConstruct(line));
			printTopHits(hits);
		}
		System.out.println("exit");
	}

	public static Query queryConstruct(String queryTerms) throws ParseException {
		if (queryTerms.indexOf("*") != -1) {
			return getWildCardQuery(queryTerms);
		}
		if (queryTerms.indexOf(" ") != -1) {
			return getPhraseQuery(queryTerms);
		}
		return getQuery(queryTerms);
	}

	public static Query getQuery(String queryTerms) throws ParseException {
		QueryParser queryParser = new QueryParser("contents", analyzer);
		Query query = queryParser.parse(queryTerms);
		System.out.println("Searching for: " + query.toString("contents"));
		return query;
	}

	public static TermQuery getTermQuery(String term) {
		return new TermQuery(new Term("contents", term));
	}

	public static PhraseQuery getPhraseQuery(String phrase) {
		PhraseQuery phraseQuery = new PhraseQuery();
		String terms[] = phrase.split(" ");
		for (int i = 0; i < terms.length; i++) {
			phraseQuery.add(new Term("contents", terms[i]));
		}
		phraseQuery.setSlop(1);
		return phraseQuery;
	}

	public static PrefixQuery getPrefixQuery(String prefix) {
		return new PrefixQuery(new Term("contents", prefix));
	}

	public static BooleanQuery getAndBooleanQuery(String queryTerms) {
		BooleanQuery booleanQuery = new BooleanQuery();
		StringTokenizer tokenizer = new StringTokenizer(queryTerms);
		while (tokenizer.hasMoreTokens()) {
			booleanQuery.add(new TermQuery(new Term("contents", tokenizer
					.nextToken())), BooleanClause.Occur.MUST);
		}
		return booleanQuery;
	}

	public static BooleanQuery getOrBooleanQuery(String queryTerms) {
		BooleanQuery booleanQuery = new BooleanQuery();
		StringTokenizer tokenizer = new StringTokenizer(queryTerms);
		while (tokenizer.hasMoreTokens()) {
			booleanQuery.add(new TermQuery(new Term("contents", tokenizer
					.nextToken())), BooleanClause.Occur.SHOULD);
		}
		return booleanQuery;
	}

	public static Query getWildCardQuery(String queryTerm) {
		if (queryTerm.indexOf("*") != -1) {
			return new WildcardQuery(new Term("contents", queryTerm));
		}
		return new TermQuery(new Term("contents", queryTerm));
	}

	static void printTopHits(Hits hits) throws IOException {
		final int HITS_COUNT = 50;
		if (hits == null || hits.length() == 0) {
			System.out.println("0 documents matched");
			return;
		}
		System.out.println(hits.length() + " documents matched");
		for (int i = 0; i < HITS_COUNT && i < hits.length(); i++) {

			System.out.println("rank = " + (i + 1) + "\t score="
					+ hits.score(i) + "\tfile=" + hits.doc(i).get("path"));
		}
	}
}
